package ua.khpi.si.kit49.diploma.controllers;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.gson.Gson;

import ua.khpi.si.kit49.diploma.core.Constants;
import ua.khpi.si.kit49.diploma.core.JsonRegistrationMessage;
import ua.khpi.si.kit49.diploma.db.dto.User;
import ua.khpi.si.kit49.diploma.db.dto.UserRole;
import ua.khpi.si.kit49.diploma.service.RegistrationService;
import ua.khpi.si.kit49.diploma.util.RegistrationValidator;

/**
 * Controller for admin's functionality
 * 
 * @author netstalk3r
 * 
 */

@Controller
public class AdminController {
	
	// ////////////////////////////////////////////////////////////////
	// mapping for methods
	// ////////////////////////////////////////////////////////////////
	private static final String ADD_USER_PAGE_MAPPING = "/addUser";
	private static final String USERS_PAGE_MAPPING = "/users";
	private static final String USER_PAGE_MAPPING = "/user/{username}";
	private static final String USER_UPDATE_MAPPING = "/user";
	private static final String REMOVE_USERS_MAPPING = "/remove";
	private static final String BAN_USERS_MAPPING = "/ban";
	private static final String UNBAN_USERS_MAPPING = "/unban";
	// ////////////////////////////////////////////////////////////////

	// ////////////////////////////////////////////////////////////////
	// constants to determine what to do with the user
	// ////////////////////////////////////////////////////////////////
	private static final Boolean BAN = false;
	private static final Boolean UNBAN = true;
	// ////////////////////////////////////////////////////////////////
	
	/**
	 * Logger
	 */
	private static final Logger log = Logger.getLogger(AdminController.class);

	/**
	 * message recourse
	 */
	@Autowired(required = true)
	private ReloadableResourceBundleMessageSource messageSource;

	/**
	 * validator for validate data of new user
	 */
	@Autowired(required = true)
	RegistrationValidator registrationValidator;

	/**
	 * service for register, ban, unban, remove users
	 */
	@Autowired(required = true)
	RegistrationService registrationService;

	/**
	 * method for getting add user page
	 * 
	 * @param model
	 *            model map
	 * @param user
	 *            for add
	 * @param loc
	 *            current localization
	 * @return add page
	 */
	@RequestMapping(value = ADD_USER_PAGE_MAPPING, method = RequestMethod.GET)
	public String getAddUserPage(ModelMap model,
			@ModelAttribute("user") User user, Locale loc) {
		log.info("Get add user page");
		log.debug("Language - " + loc.getLanguage());
		return Constants.ADD_USER_PAGE;
	}

	/**
	 * method for register new users
	 * 
	 * @param model
	 *            model map
	 * @param user
	 *            to register
	 * @param isAdmin
	 *            determines who will be register
	 * @param confirmPass
	 *            to check passwords
	 * @param loc
	 *            current localization
	 * @return message with information about errors or success
	 */
	@RequestMapping(value = ADD_USER_PAGE_MAPPING, method = RequestMethod.POST)
	@ResponseBody
	public String getAddUserPage(ModelMap model,
			@ModelAttribute("user") User user,
			@RequestParam("role") Boolean isAdmin,
			@RequestParam("conf-password") String confirmPass, Locale loc) {

		log.info("Admin registration controller work");
		log.debug("Language - " + loc.getLanguage());

		JsonRegistrationMessage jsonRegistrationMessage = new JsonRegistrationMessage();

		registrationValidator.validate(user, confirmPass,
				jsonRegistrationMessage, loc, true);

		if (jsonRegistrationMessage.isValid()) {
			registrationService.registerUser(user, isAdmin);
		}

		Gson gson = new Gson();

		String reply = gson.toJson(jsonRegistrationMessage);

		log.info("Reply: " + reply);

		log.info("Admin registration controller finished");
		return reply;
	}

	/**
	 * method for getting page with all users
	 * 
	 * @param model
	 *            model map
	 * @param loc
	 *            current localization
	 * @return page with all users
	 */
	@RequestMapping(value = USERS_PAGE_MAPPING, method = RequestMethod.GET)
	public String getUsersPage(ModelMap model, Locale loc) {
		log.info("Get users page");
		log.debug("Language - " + loc.getLanguage());
		model.put("user", new User());
		model.put("users", registrationService.getAllUsers());
		return Constants.USERS_PAGE;
	}

	/**
	 * method for removing users
	 * 
	 * @param model
	 *            model map
	 * @param removeIds
	 *            list with users id to remove
	 * @param loc
	 *            current localization
	 * @return redirect to users page
	 */
	@RequestMapping(value = REMOVE_USERS_MAPPING, method = RequestMethod.POST)
	public String removeUsers(ModelMap model,
			@RequestParam("remove") String removeIds, Locale loc) {
		log.debug("List with id to remove: " + removeIds);
		List<Integer> remove = new ArrayList<Integer>();
		try {
			StringTokenizer stringTokenizer = new StringTokenizer(removeIds,
					",");
			while (stringTokenizer.hasMoreTokens()) {
				remove.add(Integer.parseInt(stringTokenizer.nextToken()));
			}
		} catch (NumberFormatException e) {
			log.error(e.getMessage());
			String errorMessage = messageSource.getMessage(
					"company.error.city.illegal.id.format", null,
					Constants.DEFAULT_MESSAGE, loc);
			errorMessage = StringEscapeUtils.unescapeJava(errorMessage);
			model.put("errorMessage", errorMessage);
			return Constants.ERROR_PAGE;
		}
		registrationService.removeUsers(remove);
		return "redirect:/pages" + USERS_PAGE_MAPPING;
	}

	/**
	 * method for ban users
	 * 
	 * @param model
	 *            model map
	 * @param banIds
	 *            list with user's id to ban
	 * @param loc
	 *            current localization
	 * @return redirect to users page
	 */
	@RequestMapping(value = BAN_USERS_MAPPING, method = RequestMethod.POST)
	public String banUsers(ModelMap model, @RequestParam("ban") String banIds,
			Locale loc) {
		log.debug("List with id to ban: " + banIds);
		List<Integer> ban = new ArrayList<Integer>();
		try {
			StringTokenizer stringTokenizer = new StringTokenizer(banIds, ",");
			while (stringTokenizer.hasMoreTokens()) {
				ban.add(Integer.parseInt(stringTokenizer.nextToken()));
			}
		} catch (NumberFormatException e) {
			log.error(e.getMessage());
			String errorMessage = messageSource.getMessage(
					"company.error.city.illegal.id.format", null,
					Constants.DEFAULT_MESSAGE, loc);
			errorMessage = StringEscapeUtils.unescapeJava(errorMessage);
			model.put("errorMessage", errorMessage);
			return Constants.ERROR_PAGE;
		}
		registrationService.banUnbanUsers(ban, BAN);
		return "redirect:/pages" + USERS_PAGE_MAPPING;
	}

	/**
	 * method for unban users
	 * 
	 * @param model
	 *            model map
	 * @param unbanIds
	 *            list with user's id to unban
	 * @param loc
	 *            current localization
	 * @return redirect to users page
	 */
	@RequestMapping(value = UNBAN_USERS_MAPPING, method = RequestMethod.POST)
	public String unbanUsers(ModelMap model,
			@RequestParam("unban") String unbanIds, Locale loc) {
		log.info("List with id to unban: " + unbanIds);
		List<Integer> unban = new ArrayList<Integer>();
		try {
			StringTokenizer stringTokenizer = new StringTokenizer(unbanIds, ",");
			while (stringTokenizer.hasMoreTokens()) {
				unban.add(Integer.parseInt(stringTokenizer.nextToken()));
			}
		} catch (NumberFormatException e) {
			log.error(e.getMessage());
			String errorMessage = messageSource.getMessage(
					"company.error.city.illegal.id.format", null,
					Constants.DEFAULT_MESSAGE, loc);
			errorMessage = StringEscapeUtils.unescapeJava(errorMessage);
			model.put("errorMessage", errorMessage);
			return Constants.ERROR_PAGE;
		}
		registrationService.banUnbanUsers(unban, UNBAN);
		return "redirect:/pages" + USERS_PAGE_MAPPING;
	}

	/**
	 * method for get information about particular user
	 * 
	 * @param model
	 *            model map
	 * @param user
	 *            particular user
	 * @param username
	 *            determine user
	 * @param loc
	 *            particular user
	 * @return page with information about current user
	 */
	@RequestMapping(value = USER_PAGE_MAPPING, method = RequestMethod.GET)
	public String getUserPage(ModelMap model,
			@ModelAttribute("user") User user,
			@PathVariable("username") String username, Locale loc) {
		model.put("user", registrationService.getUserByUsername(username));
		return Constants.USER_PAGE;
	}

	/**
	 * method for update user's
	 * 
	 * method does not use
	 * 
	 * @param model
	 *            model map
	 * @param user
	 *            user to update
	 * @param confirmPass
	 *            to check passwords
	 * @param role
	 *            of this user
	 * @param loc
	 *            particular user
	 * @return message with information about errors or success
	 */
	@RequestMapping(value = USER_UPDATE_MAPPING, method = RequestMethod.POST)
	@ResponseBody
	public String setUser(ModelMap model, @ModelAttribute("user") User user,
			@RequestParam("conf-password") String confirmPass,
			@RequestParam("role") String role, Locale loc) {

		log.info("Update user with username - " + user.getUsername());
		log.info(role);
		log.debug("Language - " + loc.getLanguage());

		JsonRegistrationMessage jsonRegistrationMessage = new JsonRegistrationMessage();

		registrationValidator.validate(user, confirmPass,
				jsonRegistrationMessage, loc, false);

		if (jsonRegistrationMessage.isValid()) {
			registrationValidator.validateRole(jsonRegistrationMessage, role,
					loc);
			if (jsonRegistrationMessage.isValid()) {
				UserRole userRole = new UserRole();
				userRole.setAuthority(role);
				user.setUserRole(userRole);
				registrationService.updateUser(user);
			}
		}

		Gson gson = new Gson();

		String reply = gson.toJson(jsonRegistrationMessage);

		log.info("Reply: " + reply);

		return reply;
	}

	/**
	 * Map with roles
	 * 
	 * @param loc
	 *            particular user
	 * @return map with roles
	 */
	@ModelAttribute("roleList")
	public Map<Boolean, String> booleanList(Locale loc) {

		Map<Boolean, String> roles = new LinkedHashMap<Boolean, String>();

		String role = messageSource.getMessage("company.roles.role.user", null,
				Constants.DEFAULT_MESSAGE, loc);
		role = StringEscapeUtils.unescapeJava(role);
		roles.put(false, role);

		role = messageSource.getMessage("company.roles.role.admin", null,
				Constants.DEFAULT_MESSAGE, loc);
		role = StringEscapeUtils.unescapeJava(role);
		roles.put(true, role);

		return roles;
	}

}
